import _thread

import numpy as np
from PyEMD import EMD, Visualisation
import matplotlib.pyplot as plt
# 构建信号
# 时间t: 为0到1s,采样频率为100Hz，S为合成信号
from pandas import read_csv, DataFrame
from sklearn.preprocessing import MinMaxScaler
from statsmodels.graphics.tsaplots import plot_pacf
from tensorflow.python.keras.utils.np_utils import to_categorical
from keras.layers import LSTM, RepeatVector, Dense, \
    Activation, Add, Reshape, Input, Lambda, Multiply, Concatenate, Dot
from util import series_to_supervised, TIME_STEP, draw_data
import keras
from sklearn.metrics import mean_squared_error, mean_absolute_error
from tensorflow.python.keras.callbacks import EarlyStopping
def getFlowData():
    # 切换19年和20年数据只需要改下面两行
    multi_dataset = read_csv('./data/2019allday.csv', header=0, index_col=0)
    dataset = DataFrame()
    # 取in_card_flow(流出机场客流)、实际降落载客数 arr_ALDT_passenger、时段、天气作为参数，预测in_card_flow
    dataset['in_flow'] = multi_dataset['in_flow']
    # 将NAN替换为0
    dataset.fillna(0, inplace=True)
    values = dataset.values.flatten()
    return values

def getArr_ALDT():
    # 切换19年和20年数据只需要改下面两行
    multi_dataset = read_csv('./data/2019allday.csv', header=0, index_col=0)
    dataset = DataFrame()
    dataset['arr_ALDT_passenger'] = multi_dataset['arr_ALDT_passenger']
    # 将NAN替换为0
    dataset.fillna(0, inplace=True)
    values = dataset.values.flatten()
    return values
# PARAMETER_NUM: 分解出的本征函数个数+残波个数
def getModel(input_num):
    inputs = []
    lstms = []
    for i in range(input_num):
        input_temp = Input(shape=(TIME_STEP, 1))  # 输入时间序列数据
        lstm_temp = keras.layers.Bidirectional(LSTM(20, return_sequences=False))(input_temp)
        inputs.append(input_temp)
        lstms.append(lstm_temp)

    x = keras.layers.concatenate(lstms[:])

    output = Dense(1)(x)
    output = Reshape((-1,))(output)
    output = Dense(1)(output)  # 最后预测，代码修改点

    model = keras.models.Model(inputs=inputs[:], outputs=output)
    return model

def my_main(rate_begin, rate_end, n, file_name):
    # 获取轨道客流数据
    flowData = getFlowData()
    day_num = 26
    # 提取imfs和残波
    emd = EMD()
    emd.emd(flowData)
    imfs, res = emd.get_imfs_and_residue()

    # 获取航班实际降落载客数据
    arr_ALDT = getArr_ALDT()
    # 将航班载客数据的数量级拉到和轨道客流一致,这里使用中位数作为比例（均值和中位数的比例差不多）
    # 中位数
    # median_arr_ALDT = np.median(arr_ALDT)
    # median_flowData = np.median(flowData)
    # rate = median_arr_ALDT / median_flowData # 这里的rate=30
    # 试验不同的rate
    res = ""
    fi = open(file_name, "w") # 打开文件以便写入
    for rate in range(rate_begin, rate_end):
        arr_ALDT = arr_ALDT / rate


        values = np.vstack((imfs, arr_ALDT))
        input_num = values.shape[0]

        # 把输入整理成 n个time_step的形式，输出是下一个时间片的真实客流
        inputs = []
        for i in range(input_num):
            input_temp = series_to_supervised(values[i].tolist(), TIME_STEP, 1)
            input_temp.drop(input_temp.columns[[-1]], axis=1, inplace=True)
            inputs.append(input_temp)
        inputs = np.array(inputs)
        # 构建输出数据
        output = flowData.tolist()[TIME_STEP:]

        # 分为训练集测试集
        n_train_time_slice = (day_num - 1) * 100
        inputs_train = inputs[:, :n_train_time_slice, :]
        inputs_test = inputs[:, n_train_time_slice:, :]

        output_train = output[:n_train_time_slice]
        output_test = output[n_train_time_slice:]

        # 重塑成3D形状 [样例, 时间步, 特征]
        inputs_train = inputs_train.reshape((inputs_train.shape[0], inputs_train.shape[1], TIME_STEP, int(inputs_train.shape[2] / TIME_STEP)))
        inputs_test = inputs_test.reshape((inputs_test.shape[0], inputs_test.shape[1], TIME_STEP, int(inputs_test.shape[2] / TIME_STEP)))



        # model.fit函数中传入的输入输出，必须是ndarray格式
        output_train = np.array(output_train)
        output_test = np.array(output_test)

        model = getModel(input_num)
        model.compile(loss='mse', optimizer='adam')
        # 拟合神经网络模型
        early_stopping = EarlyStopping(monitor='val_loss', patience=20, verbose=2)

        # 把inputs的ndarray第一维转成list，才好传入model.fit函数
        inputs_train = [inputs_train[i, :, :, :] for i in range(inputs_train.shape[0])]
        inputs_test = [inputs_test[i, :, :, :] for i in range(inputs_test.shape[0])]

        mean_loss = 0
        for i in range(n):
            model.fit(inputs_train[:], output_train,
                      validation_data=(inputs_test[:], output_test),
                      callbacks=[early_stopping], verbose=2,
                      epochs=1000, batch_size=128)

            # 保存模型
            # model_save_path = "EMD+LSTM.h5"
            # model.save(model_save_path)
            # print("模型保存成功")
            yhat = model.predict(inputs_test[:])
            mse = mean_squared_error(output_test, yhat)
            # print('Test MSE: %.3f' % mse)
            # pic_path = "./picture/EMD+LSTM.png"
            # pic_title = "EMD\n MSE=%.3f" % mse
            # draw_data(yhat, output_test, pic_path, pic_title)
            mean_loss = mean_loss + mse
        mean_loss = mean_loss / n
        print("rate=%d,mse=%f" % (rate, mean_loss), file=fi)
        res = res + "rate=%d,mse=%f\n" % (rate, mean_loss)
    print(res)
    print("线程执行结束")

if __name__ == '__main__':
    # try:
    # _thread.start_new_thread(my_main, (20, 25, 5, "./out1.txt"))
    # _thread.start_new_thread(my_main, (25, 30, 5, "./out2.txt"))
    # _thread.start_new_thread(my_main, (30, 35, 5, "./out3.txt"))
    # _thread.start_new_thread(my_main, (35, 40, 5, "./out4.txt"))
    my_main(43, 44, 5, "./out6.txt")
    # _thread.start_new_thread(my_main, (45, 50, 5, "./out6.txt"))
    # except:
    #     print("Error: 无法启动线程")
    # while 1:3
    #     pass